/*
 * commons is a based project implemented
 * Copyright (C) 2024 Jasmine
 */
package com.commons.core.utils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Jasmine
 * @version 1.0
 * @date 2021-11-30 8:52:52
 * @see LocalDateTimeUtils
 * @since JDK1.8
 */
public class LocalDateTimeUtils {

    /**
     * 自定义格式化
     */
    public static final String YEAR_MONTH_FORMATTER = "yyyy-MM";
    public static final String DATE_FORMATTER = "yyyy-MM-dd";
    public static final String DATETIME_FORMATTER = "yyyy-MM-dd HH:mm:ss";

    public static final String TIME_FORMATTER = "HH:mm:ss";
    public static final String YEAR_MONTH_FORMATTER_SHORT = "yyyyMM";
    public static final String DATE_FORMATTER_SHORT = "yyyyMMdd";

    public static final String DATETIME_FORMATTER_SHORT = "yyyyMMddHHmmss";
    public static final String TIME_FORMATTER_SHORT = "HHmmss";

    /**
     * 24小时时间正则表达式
     */
    public static final String MATCH_TIME_24 = "(([0-1][0-9])|2[0-3]):[0-5][0-9]:[0-5][0-9]";
    /**
     * 日期正则表达式
     */
    public static final String REGEX_DATA =
        "^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?("
            + "(0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|"
            + "([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))";

    public static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATETIME_FORMATTER);

    /**
     * 根据开始时间和结束时间生成时间序列
     */
    public static List<String> generateTimeSeries(LocalDateTime startTime, LocalDateTime endTime,
        DateTimeFormatter dateTimeFormatter) {
        List<String> days =
            Stream.iterate(startTime, d -> d.plusDays(1)).limit(ChronoUnit.DAYS.between(startTime, endTime) + 1)
                .map(value -> value.format(dateTimeFormatter)).collect(Collectors.toList());
        return days;
    }

    /**
     * 日期格式化字符串
     *
     * @param localDate 日期
     * @param pattern 格式化
     */
    public static String formatLocalDate(LocalDate localDate, String pattern) {
        return localDate.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 时间格式化字符串
     *
     * @param localTime 时间
     * @param pattern 格式化
     */
    public static String formatLocalTime(LocalTime localTime, String pattern) {
        return localTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 日期时间格式化字符串
     *
     * @param localDateTime 日期时间
     * @param pattern 格式化
     */
    public static String formatLocalDateTime(LocalDateTime localDateTime, String pattern) {
        return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 日期字符串转日期
     *
     * @param date 日期字符串
     * @param pattern 格式化
     */
    public static LocalDate parseLocalDate(String date, String pattern) {
        return LocalDate.parse(date, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 时间字符串转时间
     *
     * @param time 时间字符串
     * @param pattern 格式化
     */
    public static LocalTime parseLocalTime(String time, String pattern) {
        return LocalTime.parse(time, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 日期时间字符串转日期时间
     *
     * @param dateTime 日期时间字符串
     * @param pattern 格式化
     */
    public static LocalDateTime parseLocalDateTime(String dateTime, String pattern) {
        return LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 获取当前星期
     *
     * @return 1:星期一、2:星期二、3:星期三、4:星期四、5:星期五、6:星期六、7:星期日
     */
    public static int getCurrentWeek() {
        return LocalDate.now().getDayOfWeek().getValue();
    }

    /**
     * 获取当前星期
     */
    public static int getWeek(LocalDate localDate) {
        return localDate.getDayOfWeek().getValue();
    }

    /**
     * 获取指定日期的星期
     *
     * @param date 日期字符串
     * @param pattern 格式化
     */
    public static int getWeek(String date, String pattern) {
        return parseLocalDate(date, pattern).getDayOfWeek().getValue();
    }

    /**
     * 日期相隔年数
     *
     * @param startLocalDateTime 起日期
     * @param endLocalDateTime 止日期
     */
    public static int intervalYears(LocalDateTime startLocalDateTime, LocalDateTime endLocalDateTime) {
        return endLocalDateTime.getYear() - startLocalDateTime.getYear();
    }

    /**
     * 日期相隔月数
     *
     * @param startLocalDateTime 起日期
     * @param endLocalDateTime 止日期
     */
    public static int intervalMonths(LocalDateTime startLocalDateTime, LocalDateTime endLocalDateTime) {
        int value = (endLocalDateTime.getYear() - startLocalDateTime.getYear()) * 12
            + (endLocalDateTime.getMonthValue() - startLocalDateTime.getMonthValue());
        return value;
    }

    /**
     * 日期相隔天数
     *
     * @param startLocalDate 起日期
     * @param endLocalDate 止日期
     */
    public static long intervalDays(LocalDate startLocalDate, LocalDate endLocalDate) {
        return endLocalDate.toEpochDay() - startLocalDate.toEpochDay();
    }

    /**
     * 日期相隔小时
     *
     * @param startLocalDateTime 起日期时间
     * @param endLocalDateTime 止日期时间
     */
    public static long intervalHours(LocalDateTime startLocalDateTime, LocalDateTime endLocalDateTime) {
        return Duration.between(startLocalDateTime, endLocalDateTime).toHours();
    }

    /**
     * 日期相隔分钟
     *
     * @param startLocalDateTime 起日期时间
     * @param endLocalDateTime 止日期时间
     */
    public static long intervalMinutes(LocalDateTime startLocalDateTime, LocalDateTime endLocalDateTime) {
        return Duration.between(startLocalDateTime, endLocalDateTime).toMinutes();
    }

    /**
     * 日期相隔秒数
     *
     * @param startLocalDateTime 起日期时间
     * @param endLocalDateTime 止日期时间
     */
    public static long intervalSeconds(LocalDateTime startLocalDateTime, LocalDateTime endLocalDateTime) {
        long seconds = Duration.between(startLocalDateTime, endLocalDateTime).toMillis() / 1000;
        return seconds;
        // TODO sinceJDK9 return Duration.between(startLocalDateTime, endLocalDateTime).toSeconds();
    }

    /**
     * 日期相隔毫秒数
     *
     * @param startLocalDateTime 起日期时间
     * @param endLocalDateTime 止日期时间
     */
    public static long intervalMillis(LocalDateTime startLocalDateTime, LocalDateTime endLocalDateTime) {
        return Duration.between(startLocalDateTime, endLocalDateTime).toMillis();
    }

    /**
     * 当前是否闰年
     */
    public static boolean isCurrentLeapYear() {
        return LocalDate.now().isLeapYear();
    }

    /**
     * 是否闰年
     */
    public static boolean isLeapYear(LocalDate localDate) {
        return localDate.isLeapYear();
    }

    /**
     * 是否当天
     *
     * @param localDate 日期
     */
    public static boolean isToday(LocalDate localDate) {
        return LocalDate.now().equals(localDate);
    }

    /**
     * LocalDate转换成Date
     *
     * @param localDate
     * @return
     */
    public static Date localDateToDate(LocalDate localDate) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
        return Date.from(instant);
    }

    /**
     * 24小时时间校验
     */
    public static boolean isValidate24(String time) {
        Pattern p = Pattern.compile(MATCH_TIME_24);
        return p.matcher(time).matches();
    }
}
